/*
 * Copyright:  2018 smarabbit studio.
 *
 *  Licensed under the Confluent Community License; you may not use this file
 *  except in compliance with the License.  You may obtain a copy of the License at
 *
 *  http://www.confluent.io/confluent-community-license
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 *  WARRANTIES OF ANY KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations under the License.
 *
 *  @作   者： 黄开晖 (117227773@qq.com)
 *  @日   期:  2020年8月30日
 */
package com.massyframework.beanskin.runtime.service;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;
import	java.util.function.Predicate;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.massyframework.beanskin.Module;
import com.massyframework.beanskin.service.Filter;
import com.massyframework.beanskin.service.ServiceEvent;
import com.massyframework.beanskin.service.ServiceListener;
import com.massyframework.beanskin.service.ServiceUnregistingEvent;

/**
 * {@link ServiceEventPublisher} 管理服务监听器，并在服务事件发生时，将事件推送给服务监听器处理
 */
class ServiceEventPublisher{

    private Logger logger;
    private List<ListenerWrapper> listeners;

    /**
     * 构造方法
     */
    public ServiceEventPublisher(){
    	this.logger = LoggerFactory.getLogger(ServiceEventPublisher.class);
        this.listeners = new CopyOnWriteArrayList<>();
    }


    /**
     * 添加事件监听器和对应的服务过滤器
     * @param module {@link Module}, 注册事件监听器的模块
     * @param listener {@link ServiceListener}, 服务事件监听器
     * @param filter {@link Filter}， 服务过滤事件
     */
    public void addListener(Module<?> module, ServiceListener listener, Filter filter){
        ListenerWrapper wrapper =
                new ListenerWrapper(module, listener, filter);
        this.listeners.add(wrapper);
        if (logger.isDebugEnabled()){
            logger.debug("add ServiceListener: " + listener.getClass().getName() + ".");
        }
    }

    /**
     * 移除事件监听器
     * @param module {@link Module}, 注册事件监听器的模块
     * @param listener {@link ServiceListener}, 服务事件监听器
     */
    public void removeListener(Module<?> module, ServiceListener listener){
        List<ListenerWrapper> founds = new ArrayList<>();
        for (ListenerWrapper wrapper: this.listeners){
            if (wrapper.isMatch(module, listener)){
                founds.add(wrapper);
            }
        }

        this.listeners.removeAll(founds);
        if (logger.isDebugEnabled()){
            logger.debug("remove ServiceListener: " + listener.getClass().getName() + ".");
        }
    }

    /**
     * 发布服务注销事件
     * @param event {@link ServiceUnregistingEvent}. 服务注销事件
     * @param allowAccess {@link Predicate}, 是否允许访问的断言
     */
    public <S> void applyEvent(ServiceEvent<S> event, Predicate<String>  allowAccess){
    	for (ListenerWrapper wrapper: this.listeners){
            wrapper.onChanged(event);
        }
    }

    /**
     * 日志记录器
     * @return {@link Logger}
     */
    protected Logger getLogger(){
        return this.logger;
    }

    private class ListenerWrapper implements ServiceListener {

        private final Module<?> module;
        private final ServiceListener listener;
        private final Filter filter;

        public ListenerWrapper(Module<?> module, ServiceListener listener, Filter filter) {
            this.module = Objects.requireNonNull(module,  "\"module\" cannot be null.");
            this.listener = Objects.requireNonNull(listener, "\"listener\" cannot be nul.");
            this.filter = Objects.requireNonNull(filter, "\"filter\" cannot be null.");
        }

        /**
         * 当<code>event</code>事件触发时，对事件进行处理
         *
         * @param event {@link ServiceEvent}
         */
        @Override
        public void onChanged(ServiceEvent<?> event) {
            if (filter.match(event.getServiceReference())) {
                try {
                    this.listener.onChanged(event);
                }catch(Exception e) {
                    Logger logger = getLogger();
                    if (logger != null) {
                        if (logger.isErrorEnabled()) {
                            logger.error(this.listener.getClass().getName() + " onChanged() failed.", e);
                        }
                    }
                }
            }
        }

        /**
         * 判断是否来自{@code module}的注册
         * @param module {@link Module}, 模块
         * @return {@link boolean}, 返回{@code true}表示事件监听器是来自{@code module}的注册
         */
        @SuppressWarnings("unused")
		public boolean isRegisterBy(Module<?> module){
            return this.module.equals(module);
        }

        /**
         * 判断是否相同的监听器
         * @param module {@link Module}
         * @param listener {@link ServiceListener}
         * @return {@link boolean}, 返回<code>true</code>表示是相同的事件监听器，否则返回<code>false</code>
         */
        public boolean isMatch(Module<?> module, ServiceListener listener){
            return this.module.equals(module) && (this.listener == listener);
        }

        /**
         * 注册监听器的模块
         * @return {@link Module}
         */
		@SuppressWarnings("unused")
		public Module<?> getModule(){
            return this.module;
        }
    }
}

